﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using NUnit.Framework;
using SQLRunnerLib.Project;
using SQLServices.Runners;
using SQLServices.TransMgr;
using SQLTests.Framework;
using SQLRunnerLib.Services;

namespace SQLTests.EndToEnd
{
    public class BasicScriptsTestFixture : AbstractTest
    {

        public BasicScriptsTestFixture() : base() { }

        #region Tests

        /// <summary>
        /// Execute some basic scripts against a SQL Server
        /// It creates a new database, then a table and inserts one record
        /// It also deletes the database itself
        /// </summary>
        [Test]
        public void CreateSqlProject()
        {
            ExecuteScripts("basicscripts", ConnectionMgrType.StrictConnMgr);
        }

        [Test]
        public void ConnMgrStrict()
        {
            ExecuteConnMgrScripts(ConnectionMgrType.StrictConnMgr);
        }

        [Test]
        public void ConnMgrCommit()
        {
            ExecuteConnMgrScripts(ConnectionMgrType.CommitTransactionConnMgr);
        }

        [Test]
        public void ConnMgrOptimistic()
        {
            ExecuteConnMgrScripts(ConnectionMgrType.OptimisticConnMgr);
        }

        [Test]
        public void ConnMgrPessimist()
        {
            ExecuteConnMgrScripts(ConnectionMgrType.PessimistConnMgr);
        }

        [Test]
        public void ConnMgrRollback()
        {
            ExecuteConnMgrScripts(ConnectionMgrType.RollbackTransactionConnMgr);
        }

        #endregion

        #region Helper Methods

        private void ExecuteScripts(string folderPath, ConnectionMgrType connMgr)
        {
            ErrorMsg = string.Empty;
            IRunner runner = GetRunner(folderPath);
            runner.ScriptExecError += RunnerScriptExecError;
            runner.ConnectionMgrType = connMgr;
            runner.RunScripts();
            if (ErrorMsg != string.Empty)
                throw new ApplicationException(ErrorMsg);
        }

        private IRunner GetRunner(string folderPath)
        {
            SQLProject proj = GetProject(folderPath);
            // Note: Windows Authentication is always used
            ServiceContainer.Instance.SQLConnection.OpenConnection(Settings.Default.ServerName, "", "", true);
            ServiceContainer.Instance.SQLConnection.GetDatabase("Master");
            //TODO: Work out what this would have done.
            SQLEnvironment environmentToRun = proj.SelectedEnvironment;
            return SQLRunnerLib.Services.ServiceContainer.CreateRunner(proj, environmentToRun, ConnectionMgrType.CommitTransactionConnMgr);
        }

        private SQLProject GetProject(string folderPath)
        {
            SQLProject proj = new SQLProject();
            proj.Extensions.Add("sql");

            string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Settings.Default.ScriptsPath);
            path = Path.Combine(path, folderPath);
            Assert.IsTrue(Directory.Exists(path), "Scripts folder was not found: " + path);
            var folder = new Folder()
                             {
                                 Path = path,
                                 IncludeAllFiles = true,
                                 IncludeAllSubFolders = false
                             };
            
            proj.Folders.Add(folder);
            return proj;
        }

        #endregion
        #region Connection Manager Test Helper Methods

        private void FixtureCreation()
        {
            ExecuteScripts("createTestDatabase", ConnectionMgrType.StrictConnMgr);            
        }

        private void FixtureTearDown()
        {
            ExecuteScripts("deleteTestDatabase", ConnectionMgrType.StrictConnMgr);            
        }

        private void ExecuteConnMgrScripts(ConnectionMgrType type)
        {
            FixtureCreation();
            ExecuteScripts("connMgrScripts", type);            
            FixtureTearDown();
        }

        #endregion
        #region Script Error Handler

        private string ErrorMsg = string.Empty;

        public void RunnerScriptExecError(object sender, SQLServices.Runners.Events.ScriptExecutionErrorEventArgs e)
        {
            var msg = String.Format("An error executing [{0}]: {1}", e.FileName, e.ErrorMsg);
            if (ErrorMsg == string.Empty)
                ErrorMsg = msg;
            else
            {
                ErrorMsg += "\n" + msg;
            }
        }

        #endregion

        #region Overrides of AbstractTest

        [TestFixtureSetUp]
        protected override void SetUpFixtures()
        {
            
        }

        #endregion
    }
}
